﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml;
using System.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Configuration;
using System.Security.Cryptography;
using WSMX_Invoice.MX.Invoice.Version32;

namespace WSMX_Invoice.MX.Providers
{
    public class Prov_Tralix : Provider
    {
        public const string xmlResponseError = "cfdi:Error";
        public const string xmlResponseTimbre = "tfd:TimbreFiscalDigital";

        /// <summary>
        /// Clase para timbrar un comprobante
        /// </summary>
        /// <param name="_rutaComprobante">Ruta fisica del Comprobante</param>
        /// <returns>True si se pudo timbrar correctamente</returns>
        public override Boolean Timbra(string _rutaComprobante)
        {
            bool ret = true;
            string xmlBody = "";
            string stimbre = "";
            string pathTimbre = _rutaComprobante.Substring(0, _rutaComprobante.Length - 4) + "_Timbre.xml";

            if(String.IsNullOrEmpty(EndPoint))
                throw new ArgumentNullException(EndPoint);

            if (String.IsNullOrEmpty(CustomerKey))
                throw new ArgumentNullException(CustomerKey);

            if (String.IsNullOrEmpty(_rutaComprobante))
                throw new ArgumentNullException(_rutaComprobante);

            System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) =>
            {
                return true;
            };

            Comprobante comprobante = Comprobante.LoadFromFile(_rutaComprobante);
            xmlBody = comprobante.Serialize();
            xmlBody = xmlBody.Substring(23, xmlBody.Length - 23); // Quita la definicion del <?xml version=\"1.0\"?>

            string msj = Execute(xmlBody);            

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(Functions.String2Stream(msj));
            XmlNodeList nodes = xmlDoc.GetElementsByTagName(xmlResponseTimbre);
            foreach (XmlNode childrenNode in nodes)
            {
                stimbre = childrenNode.OuterXml;
            }

            if (string.IsNullOrEmpty(stimbre))
            {
                XmlNodeList nodeError = xmlDoc.GetElementsByTagName(xmlResponseError);
                foreach (XmlNode childrenNode in nodeError)
                {
                    Errocode = childrenNode.Attributes["codigo"].Value;
                    Error = childrenNode.FirstChild.InnerText;
                    stimbre = "ERROR";
                    ret = false;
                }
            }

            if (!string.IsNullOrEmpty(stimbre) && stimbre != "ERROR")
            {
                Functions.writeFile(pathTimbre, Provider.xmlHeader + stimbre);
                TimbreFiscalDigital timbre = TimbreFiscalDigital.LoadFromFile(pathTimbre);
                timbre.SaveToFile(pathTimbre);
                comprobante.Complemento.Any.Add(FunctionsXML.GetRootElement(timbre.Serialize()));
                comprobante.SaveToFile(_rutaComprobante);

            }            

            return ret;
        }        

        /// <summary>
        /// Clase para validar un comprobante Fiscal
        /// </summary>
        /// <param name="_rutaComprobante">Ruta fisica del Comprobante</param>
        /// <returns>True si se pudo validar correctamente</returns>
        public override Boolean Valida(string _rutaComprobante)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Clase para cancelar un comprobante Fiscal
        /// </summary>
        /// <param name="_rutaComprobante">Ruta Comprobante</param>
        /// <returns>True si se pudo Cancelar el comprobante</returns>
        public override Boolean Cancela(string _rutaComprobante) 
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Execute a Soap WebService call
        /// </summary>
        public string Execute(string _body)
        {
            string soapResult = "";
            HttpWebRequest request = CreateWebRequest(EndPoint);
            XmlDocument soapEnvelopeXml = new XmlDocument();
            string xmlRequest = " <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                //+ " xmlns:ns1=\"http://www.sat.gob.mx/cfd/2\" " 
                //+ " xmlns:req=\"http://www.buzonfiscal.com/ns/xsd/bf/RequestEnviaCFD\" "
                //+ " xmlns:ns=\"http://www.buzonfiscal.com/ns/xsd/bf/bfenviacfd/1\" "
                 + " xmlns:new=\"http://new.webservice.namespace\" "
                + ">"
                + "<soapenv:Header/>"
                + "<soapenv:Body> "
                + _body
                + "</soapenv:Body>"
                + "</soapenv:Envelope>";

            soapEnvelopeXml.LoadXml(xmlRequest);

            using (Stream stream = request.GetRequestStream())
            {
                soapEnvelopeXml.Save(stream);
            }


            try
            {
                using (WebResponse response = request.GetResponse())
                {
                    using (StreamReader rd = new StreamReader(response.GetResponseStream()))
                    {
                        soapResult = rd.ReadToEnd();
                    }
                }
            }
            catch (Exception e)
            {
                if (e is WebException && ((WebException)e).Status == WebExceptionStatus.ProtocolError)
                {
                    WebResponse errResp = ((WebException)e).Response;
                    using (Stream respStream = errResp.GetResponseStream())
                    {
                        soapResult = Functions.Stream2String(respStream);
                    }
                }
                else
                {
                    soapResult = e.ToString();
                }
            }

            return soapResult;
        }

        /// <summary>
        /// Create a soap webrequest to [Url]
        /// </summary>
        /// <returns></returns>
        public HttpWebRequest CreateWebRequest(string _endpoint)
        {
            EndPoint = _endpoint;

            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(EndPoint);
            webRequest.Headers.Add("SOAPAction:\"urn:TimbradoCFD\"");

            if (!String.IsNullOrEmpty(CustomerKey))
                webRequest.Headers.Add("CustomerKey:" + CustomerKey + "");

            webRequest.ContentType = "text/xml;charset=\"UTF-8\"";
            webRequest.Accept = "text/xml";
            webRequest.Method = "POST";
            return webRequest;
        }
    }
}
